home *** CD-ROM | disk | FTP | other *** search
/ Almathera Ten Pack 3: CDPD 3 / Almathera Ten on Ten - Disc 3: CDPD3.iso / scope / 101-125 / scopedisk109 / ms-dos / src / hanlock.c < prev    next >
C/C++ Source or Header  |  1995-03-19  |  20KB  |  744 lines

  1. /*-
  2.  * $Id: hanlock.c,v 1.4 90/01/27 20:22:17 Rhialto Exp $
  3.  * $Log:       hanlock.c,v $
  4.  * Revision 1.4  90/01/27  20:22:17  Rhialto
  5.  * Added extra check when freeing MSFileLocks.
  6.  * 
  7.  * Revision 1.3  90/01/23  00:36:57  Rhialto
  8.  * Add an #ifndef READONLY.
  9.  *
  10.  * Revision 1.2  89/12/17  23:05:33  Rhialto
  11.  * Add MSSetProtect
  12.  *
  13.  * Revision 1.1  89/12/17  20:03:01  Rhialto
  14.  *
  15.  * HANLOCK.C
  16.  *
  17.  * The code for the messydos file system handler
  18.  *
  19.  * The Lock department. Takes care of operations on locks, and consequently,
  20.  * on directories.
  21.  *
  22.  * This code is (C) Copyright 1989 by Olaf Seibert. All rights reserved. May
  23.  * not be used or copied without a licence.
  24. -*/
  25.  
  26. #include "han.h"
  27. #include "dos.h"
  28.  
  29. #ifdef DEBUG
  30. #   define     debug(x)  dbprintf x
  31. #else
  32. #   define     debug(x)
  33. #endif
  34.  
  35. struct LockList *LockList;     /* List of all locked files we have. Note
  36.                                 * this is not the same as all locks we
  37.                                 * have */
  38. struct MSFileLock *RootLock;   /* Lock on root directory */
  39. struct MSFileLock *EmptyFileLock;      /* 2nd result of MSLock() */
  40.  
  41. struct DirEntry FakeRootDirEntry = {
  42.     {                          /* de_Msd */
  43.        "Unnamed ",             /* msd_Name */
  44.        "   ",                  /* msd_Ext */
  45.        ATTR_VOLUMELABEL,       /* msd_Attributes */
  46.        {0},                    /* msd_Pad1 */
  47.        0,                      /* msd_Time */
  48.        0x21,                   /* msd_Date, 1/1/80 */
  49.        0,                      /* msd_Cluster */
  50.        0                       /* msd_Filesize */
  51.     },
  52.     -1,                        /* de_Sector */
  53.     0                          /* de_Offset */
  54. };
  55. byte           DotDot[1 + 8 + 3] = "..          ";
  56.  
  57. /*
  58.  * This routine compares a name in a directory entry with a given name
  59.  */
  60.  
  61. int
  62. CompareNames(dir, name)
  63. register struct MsDirEntry *dir;
  64. register byte  *name;
  65. {
  66. #ifdef DEBUG
  67.     if (name[0] == '\\') {
  68.        extern short    DBEnable;
  69.  
  70.        DBEnable = name[1] & 0x0F;
  71.  
  72.        return CMP_END_OF_DIR;
  73.     }
  74. #endif
  75.  
  76.     if (dir->msd_Name[0] & DIR_DELETED_MASK)
  77.        return CMP_FREE_SLOT;
  78.  
  79.     if (dir->msd_Name[0] == 0)
  80.        return CMP_END_OF_DIR;  /* end of directory */
  81.  
  82.     if (dir->msd_Attributes & ATTR_VOLUMELABEL)
  83.        return CMP_NOT_EQUAL;
  84.  
  85.     if (strncmp(dir->msd_Name, name, 8 + 3))
  86.        return CMP_NOT_EQUAL;
  87.  
  88.     if (dir->msd_Attributes & ATTR_DIRECTORY)
  89.        return CMP_OK_DIR;
  90.  
  91.     return CMP_OK_FILE;
  92. }
  93.  
  94. void
  95. NextDirEntry(sector, offset)
  96. register word  *sector;
  97. register word  *offset;
  98. {
  99.     if ((*offset += MS_DIRENTSIZE) >= Disk.bps) {
  100.        *offset = 0;
  101.        if (*sector >= Disk.datablock) {
  102.            /* Must be subdirectory */
  103.            *sector = NextClusteredSector(*sector);
  104.            debug(("NextClusteredSector: %d\n", *sector));
  105.        } else {
  106.            if (++*sector >= Disk.datablock) {
  107.                *sector = SEC_EOF;
  108.            }
  109.        }
  110.     }
  111.     /* else no more work needed */
  112. }
  113.  
  114. /*
  115.  * Get the directory entry following the given one. If requested, we make
  116.  * the directory longer.
  117.  */
  118.  
  119. struct DirEntry *
  120. FindNext(previous, createit)
  121. register struct DirEntry *previous;
  122. int            createit;
  123. {
  124.     byte          *sector;
  125.     word           prevsec = previous->de_Sector;
  126.  
  127.     NextDirEntry(&previous->de_Sector, &previous->de_Offset);
  128.  
  129.     if (previous->de_Sector == SEC_EOF) {
  130.        error = ERROR_OBJECT_NOT_FOUND;
  131. #ifndef READONLY
  132.        if (createit) {
  133.            if (prevsec < Disk.datablock - 1) { /* Should not be necessary */
  134.                previous->de_Sector = prevsec + 1;
  135.            } else if (prevsec >= Disk.datablock) {
  136.                previous->de_Sector = FindFreeSector(prevsec);
  137.            }
  138.            if (previous->de_Sector != SEC_EOF) {
  139.                sector = EmptySec(previous->de_Sector);
  140.                setmem(sector, (int) Disk.bps, 0);
  141.                MarkSecDirty(sector);
  142.                FreeSec(sector);
  143.                setmem(&previous->de_Msd, sizeof (previous->de_Msd), 0);
  144.  
  145.                return previous;
  146.            }
  147.        }
  148. #endif
  149.     } else if (sector = GetSec(previous->de_Sector)) {
  150.        CopyMem(sector + previous->de_Offset, &previous->de_Msd,
  151.                (long) MS_DIRENTSIZE);
  152.        OtherEndianMsd(&previous->de_Msd);
  153.        FreeSec(sector);
  154.  
  155.        return previous;
  156.     }
  157.     return NULL;
  158. }
  159.  
  160. #ifdef DEBUG
  161.  
  162. void
  163. PrintDirEntry(de)
  164. struct DirEntry *de;
  165. {
  166.     debug(("%d,%d ", de->de_Sector, de->de_Offset));
  167.     debug(("%.8s.%.3s attr:%x time:%x date:%x start:%x size:%lx\n",
  168.           de->de_Msd.msd_Name,
  169.           de->de_Msd.msd_Ext,
  170.           de->de_Msd.msd_Attributes,
  171.           de->de_Msd.msd_Time,
  172.           de->de_Msd.msd_Date,
  173.           de->de_Msd.msd_Cluster,
  174.           de->de_Msd.msd_Filesize
  175.           ));
  176. }
  177.  
  178. #endif
  179.  
  180. /*
  181.  * MakeLock makes a struct MSFileLock from a directory entry and the
  182.  * parent directory MSFileLock pointer. It looks if it already has a Lock
  183.  * on it. In that case, it simply increments its reference count, when
  184.  * possible.
  185.  */
  186.  
  187. struct MSFileLock *
  188. MakeLock(parentdir, dir, mode)
  189. struct MSFileLock *parentdir;
  190. struct DirEntry *dir;
  191. ulong          mode;
  192. {
  193.     register struct MSFileLock *fl;
  194.     struct MSFileLock *nextfl;
  195.  
  196.     if (mode != EXCLUSIVE_LOCK || (dir->de_Msd.msd_Attributes & ATTR_DIR))
  197.        mode = SHARED_LOCK;
  198.  
  199. #ifdef DEBUG
  200.     debug(("MakeLock: "));
  201.     PrintDirEntry(dir);
  202. #endif
  203.  
  204.     /*
  205.      * Look through our list to see if we already have it. The criteria
  206.      * for this are: 1. the directory entries are the same or 2. they have
  207.      * the same first cluster and are both directories (which can have
  208.      * multiple directory entries). Sigh.
  209.      */
  210.  
  211.     for (fl = (struct MSFileLock *) LockList->ll_List.mlh_Head;
  212.         nextfl = (struct MSFileLock *) fl->msfl_Node.mln_Succ;
  213.         fl = nextfl) {
  214. #ifdef DEBUG
  215.        debug(("> "));
  216.        PrintDirEntry(&fl->msfl_Msd);
  217. #endif
  218.        if ((fl->msfl_DirSector == dir->de_Sector &&
  219.             fl->msfl_DirOffset == dir->de_Offset) ||
  220.            (fl->msfl_Msd.msd_Cluster == dir->de_Msd.msd_Cluster &&
  221.             (dir->de_Msd.msd_Attributes & ATTR_DIR) &&
  222.             (fl->msfl_Msd.msd_Attributes & ATTR_DIR))
  223.            ) {
  224.            /* Found existing lock on file */
  225.            if (fl->msfl_Refcount < 0 || mode == EXCLUSIVE_LOCK) {
  226.                error = ERROR_OBJECT_IN_USE;
  227.                return NULL;
  228.            }
  229.            fl->msfl_Refcount++;
  230.            return fl;
  231.        }
  232.     }
  233.  
  234.     fl = AllocMem((long) sizeof (*fl), MEMF_PUBLIC);
  235.     if (fl == NULL) {
  236.        error = ERROR_NO_FREE_STORE;
  237.        return NULL;
  238.     }
  239.     fl->msfl_Parent = parentdir ? MSDupLock(parentdir) : NULL;
  240.  
  241.     fl->msfl_Refcount = (mode == EXCLUSIVE_LOCK) ? -1 : 1;
  242.     fl->msfl_DirSector = dir->de_Sector;
  243.     fl->msfl_DirOffset = dir->de_Offset;
  244.     fl->msfl_Msd = dir->de_Msd;
  245.  
  246.     AddHead(&LockList->ll_List, fl);
  247.  
  248.     return fl;
  249. }
  250.  
  251. /*
  252.  * This routine Locks a file. It first searches it in the directory, then
  253.  * lets the rest of the work be done by MakeLock(). If it encounters an
  254.  * empty slot in the directory, it remembers where, in case we need it. If
  255.  * you clear the MODE_CREATEFILE bit in the mode parameter, we fabricate a
  256.  * new MSFileLock from the empty directory entry. It then becomes the
  257.  * caller's responsibility to MSUnLock() it eventually.
  258.  */
  259.  
  260. struct MSFileLock *
  261. MSLock(parentdir, name, mode)
  262. struct MSFileLock *parentdir;
  263. byte          *name;
  264. ulong          mode;
  265. {
  266.     byte          *sector;
  267.     struct MSFileLock *newlock;
  268.     register struct DirEntry *de;
  269.     struct DirEntry sde;
  270.     byte          *nextpart;
  271.     byte           component[8 + 3];   /* Note: not null-terminated */
  272.     int            createit;
  273.     word           freesec;
  274.     word           freeoffset;
  275.  
  276.     de = &sde;
  277.     newlock = NULL;
  278.  
  279.     /*
  280.      * See if we have an absolute path name (starting at the root).
  281.      */
  282.  
  283.     {
  284.        register byte  *colon;
  285.  
  286.        if (colon = index(name, ':')) {
  287.            name = colon + 1;
  288.            parentdir = RootLock;
  289.        }
  290.     }
  291.  
  292.     /*
  293.      * Get a copy of the parent dir lock, so we can walk it over the
  294.      * directory tree.
  295.      */
  296.     parentdir = MSDupLock(parentdir);
  297.  
  298.     /*
  299.      * Start with the directory entry of the parent dir.
  300.      */
  301.  
  302.     sde.de_Msd = parentdir->msfl_Msd;
  303.     sde.de_Sector = parentdir->msfl_DirSector;
  304.     sde.de_Offset = parentdir->msfl_DirOffset;
  305. #ifdef DEBUG
  306.     debug(("pdir %08lx: ", parentdir));
  307.     PrintDirEntry(&parentdir->msfl_Msd);
  308. #endif
  309.  
  310. newdir:
  311.     freesec = SEC_EOF;         /* Means none found yet */
  312.  
  313.     nextpart = ToMSName(component, name);
  314.     debug(("Component: '%11s'\n", component));
  315.     if (nextpart[0] != '/') {
  316.        nextpart = NULL;
  317. #ifndef READONLY
  318.        /*
  319.         * See if we are requested to get an empty spot in the directory
  320.         * if the given name does not exist already. The value of mode is
  321.         * not important until we actually create the filelock.
  322.         */
  323.        if (!(mode & MODE_CREATEFILE)) {
  324.            mode ^= MODE_CREATEFILE;
  325.            createit = 1;
  326.        } else
  327.            createit = 0;
  328. #endif
  329.     } else
  330.        nextpart++;
  331.  
  332.     /*
  333.      * Are we at the end of the name? Then we are finished now. This works
  334.      * because sde contains the directory entry of parentdir.
  335.      */
  336.  
  337.     if (name[0] == '\0')
  338.        goto exit;
  339.  
  340.     /*
  341.      * If there is more name, we enter the directory, and here we get the
  342.      * first entry.
  343.      */
  344.  
  345.     sde.de_Sector = DirClusterToSector(sde.de_Msd.msd_Cluster);
  346.     sde.de_Offset = 0;
  347.  
  348.     if ((sector = GetSec(sde.de_Sector)) == NULL)
  349.        goto error;
  350.  
  351.     CopyMem(sector, &sde.de_Msd, (long) sizeof (struct MsDirEntry));
  352.     OtherEndianMsd(&sde.de_Msd);
  353.     FreeSec(sector);
  354.  
  355.     while (de) {
  356.        switch (CompareNames(&sde.de_Msd, component)) {
  357.        case CMP_FREE_SLOT:
  358.            if (freesec == SEC_EOF) {
  359.                freesec = sde.de_Sector;
  360.                freeoffset = sde.de_Offset;
  361.            }
  362.            /* Fall through */
  363.        case CMP_NOT_EQUAL:
  364.            de = FindNext(&sde, createit);      /* Try next directory
  365.                                                 * entry */
  366.            continue;
  367.        case CMP_OK_DIR:
  368.            if (name = nextpart) {
  369.                /*
  370.                 * We want to keep locks on all directories between each
  371.                 * bottom directory and file lock, so we can easily find
  372.                 * the parent of a lock. There just seems to be a problem
  373.                 * here when we enter the 'subdirectories' . or .. , but
  374.                 * that in not so: MakeLock will detect that it has
  375.                 * already a lock on those, and NOT make :one/two the
  376.                 * parent of :one/two/.. .
  377.                 */
  378.                newlock = MakeLock(parentdir, de, SHARED_LOCK);
  379.                MSUnLock(parentdir);
  380.                parentdir = newlock;
  381.                goto newdir;
  382.            }
  383.            goto exit;
  384.        case CMP_OK_FILE:
  385.            if (nextpart) {
  386.                error = ERROR_OBJECT_WRONG_TYPE;
  387.                de = NULL;
  388.            }
  389.            goto exit;
  390.        case CMP_END_OF_DIR:    /* means we will never find it */
  391.            error = ERROR_OBJECT_NOT_FOUND;
  392.            if (freesec == SEC_EOF) {
  393.                freesec = sde.de_Sector;
  394.                freeoffset = sde.de_Offset;
  395.            }
  396.            de = NULL;
  397.            goto exit;
  398.        }
  399.     }
  400.  
  401. exit:
  402.     if (de) {
  403.        newlock = MakeLock(parentdir, &sde, mode);
  404.     } else {
  405.        newlock = NULL;
  406. #ifndef READONLY
  407.        if (createit &&         /* Do we want to make it? */
  408.            error == ERROR_OBJECT_NOT_FOUND &&  /* does it not exist yet? */
  409.            nextpart == NULL) { /* do we have the last part of the name */
  410.            if (freesec != SEC_EOF) {   /* is there any room? */
  411.                if (IDDiskState == ID_VALIDATED) {
  412.                    error = 0;
  413.                    setmem(&sde.de_Msd, sizeof (sde.de_Msd), 0);
  414.                    sde.de_Sector = freesec;
  415.                    sde.de_Offset = freeoffset;
  416.                    /* ToMSName(sde.de_Msd.msd_Name, name); */
  417.                    strncpy(sde.de_Msd.msd_Name, component, 8 + 3);
  418.                    EmptyFileLock = MakeLock(parentdir, &sde, mode);
  419.                    WriteFileLock(EmptyFileLock);
  420.                } else
  421.                    error = ERROR_DISK_WRITE_PROTECTED;
  422.            } else
  423.                error = ERROR_DISK_FULL;
  424.        }
  425. #endif
  426.     }
  427.  
  428. error:
  429.     MSUnLock(parentdir);
  430.  
  431.     return newlock;
  432. }
  433.  
  434. /*
  435.  * This routine DupLocks a file. This simply means incrementing the
  436.  * reference count, if it was not an exclusive Lock.
  437.  */
  438.  
  439. struct MSFileLock *
  440. MSDupLock(fl)
  441. struct MSFileLock *fl;
  442. {
  443.     if (fl == NULL)
  444.        fl = RootLock;
  445.     if (fl->msfl_Refcount <= 0) {
  446.        error = ERROR_OBJECT_IN_USE;
  447.        return NULL;
  448.     } else {
  449.        fl->msfl_Refcount++;
  450.     }
  451.  
  452.     return fl;
  453. }
  454.  
  455. /*
  456.  * This routine DupLocks the parent of a lock, if there is one.
  457.  */
  458.  
  459. struct MSFileLock *
  460. MSParentDir(fl)
  461. register struct MSFileLock *fl;
  462. {
  463.     if (fl == NULL || fl == RootLock) {
  464.        error = ERROR_OBJECT_NOT_FOUND;
  465.     } else if (fl->msfl_Parent)
  466.        return MSDupLock(fl->msfl_Parent);
  467.  
  468.     return NULL;
  469. }
  470.  
  471. /*
  472.  * This routine UnLocks a file.
  473.  */
  474.  
  475. int
  476. MSUnLock(fl)
  477. struct MSFileLock *fl;
  478. {
  479. #ifdef DEBUG
  480.     debug(("MSUnLock %08lx: ", fl));
  481.     PrintDirEntry(&fl->msfl_Msd);
  482. #endif
  483.  
  484.     if (fl) {
  485.        if (--fl->msfl_Refcount <= 0) {
  486.            struct LockList *list;
  487.  
  488.            list = (struct LockList *) fl->msfl_Node.mln_Pred;
  489.            Remove(fl);
  490.            debug(("Remove()d %08lx\n", fl));
  491.  
  492.            /*
  493.             * We may need to get rid of the LockList if it is empty. This
  494.             * is the current LockList iff we are called from
  495.             * MSDiskRemoved(). Please note that we are not even sure that
  496.             * 'list' really is the list header, therefore the careful
  497.             * test if fl refers to a volume label (root lock) which is
  498.             * finally UnLock()ed. Because of the recursion, we only try to
  499.             * free the LockList iff there is no parent anymore, since
  500.             * otherwise list may be invalid by the time we use it.
  501.             */
  502.            if (fl->msfl_Parent) {
  503.                MSUnLock(fl->msfl_Parent);
  504.            } else {
  505.                if ((fl->msfl_Msd.msd_Attributes & ATTR_VOLUMELABEL) &&
  506.                    ((void *) list->ll_List.mlh_Head ==
  507.                     (void *) &list->ll_List.mlh_Tail)
  508.                    ) {
  509.                    FreeLockList(list);
  510.                }
  511.            }
  512.            FreeMem(fl, (long) sizeof (*fl));
  513.        }
  514.     }
  515.     return DOSTRUE;
  516. }
  517.  
  518. /*
  519.  * This is (among other things) the inverse of ToMSName().
  520.  */
  521.  
  522. void
  523. ExamineDirEntry(msd, fib)
  524. struct MsDirEntry *msd;
  525. register struct FileInfoBlock *fib;
  526. {
  527.     register byte  *end,
  528.                   *dot;
  529.  
  530. #ifdef DEBUG
  531.     debug(("+ "));
  532.     PrintDirEntry(msd);
  533. #endif
  534.     strncpy(&fib->fib_FileName[1], msd->msd_Name, 8);
  535.     /* Keep at least one character, even a space, before the dot */
  536.     dot = ZapSpaces(&fib->fib_FileName[2], &fib->fib_FileName[1 + 8]);
  537.     dot[0] = ' ';
  538.     strncpy(dot + 1, msd->msd_Ext, 3);
  539.     dot[4] = '\0';
  540.     end = ZapSpaces(dot, dot + 4);
  541.     if (end > dot)
  542.        dot[0] = '.';
  543.     fib->fib_FileName[0] = strlen(&fib->fib_FileName[1]);
  544.  
  545.     fib->fib_DirEntryType =
  546.        (msd->msd_Attributes & ATTR_DIR) ? FILE_DIR : FILE_FILE;
  547.     fib->fib_Protection = 0;
  548.     if (!(msd->msd_Attributes & ATTR_ARCHIVED))
  549.        fib->fib_Protection |= FIBF_ARCHIVE;
  550.     if (msd->msd_Attributes & ATTR_READONLY)
  551.        fib->fib_Protection |= (FIBF_WRITE | FIBF_DELETE);
  552.     if (msd->msd_Attributes & (ATTR_HIDDEN|ATTR_SYSTEM))
  553.        fib->fib_Protection |= FIBF_HIDDEN;
  554.     fib->fib_Size = msd->msd_Filesize;
  555.     fib->fib_NumBlocks = (msd->msd_Filesize + Disk.bps - 1) / Disk.bps;
  556.     ToDateStamp(&fib->fib_Date, msd->msd_Date, msd->msd_Time);
  557.     fib->fib_Comment[0] = 0;
  558. }
  559.  
  560. int
  561. MSExamine(fl, fib)
  562. struct MSFileLock *fl;
  563. register struct FileInfoBlock *fib;
  564. {
  565.     if (fl == NULL)
  566.        fl = RootLock;
  567.  
  568.     fib->fib_DiskKey = ((ulong) fl->msfl_DirSector << 16) | fl->msfl_DirOffset;
  569.     fib->fib_EntryType = 0;    /* No ExNext called yet */
  570.     ExamineDirEntry(&fl->msfl_Msd, fib);
  571.  
  572.     return DOSTRUE;
  573. }
  574.  
  575. int
  576. MSExNext(fl, fib)
  577. struct MSFileLock *fl;
  578. register struct FileInfoBlock *fib;
  579. {
  580.     word           sector = fib->fib_DiskKey >> 16;
  581.     word           offset = (word) fib->fib_DiskKey;
  582.     byte          *buf;
  583.  
  584.     if (fl == NULL)
  585.        fl = RootLock;
  586.  
  587.     if (fib->fib_EntryType == 0) {
  588.        fib->fib_EntryType = 1;
  589.        if (fl->msfl_Msd.msd_Attributes & ATTR_DIR) {
  590.            /* Enter subdirectory */
  591.            sector = DirClusterToSector(fl->msfl_Msd.msd_Cluster);
  592.            offset = 0;
  593.        } else
  594.            NextDirEntry(§or, &offset);
  595.     } else {
  596. skip:
  597.        NextDirEntry(§or, &offset);
  598.     }
  599.  
  600.     if (sector != SEC_EOF) {
  601.        register struct MsDirEntry *msd;
  602.  
  603.        if (buf = GetSec(sector)) {
  604.            msd = (struct MsDirEntry *) (buf + offset);
  605.            if (msd->msd_Name[0] == '\0') {
  606.                FreeSec(buf);
  607.                goto end;
  608.            }
  609.            if (msd->msd_Name[0] & DIR_DELETED_MASK ||
  610.                msd->msd_Name[0] == '.' ||      /* Hide "." and ".." */
  611.                (msd->msd_Attributes & ATTR_VOLUMELABEL)) {
  612.                FreeSec(buf);
  613.                goto skip;
  614.            }
  615.            OtherEndianMsd(msd);/* Get correct endianness */
  616.            fib->fib_DiskKey = ((ulong) sector << 16) | offset;
  617.            ExamineDirEntry(msd, fib);
  618.            OtherEndianMsd(msd);/* Get wrong endianness */
  619.            FreeSec(buf);
  620.  
  621.            return DOSTRUE;
  622.        }
  623.     }
  624. end:
  625.     error = ERROR_NO_MORE_ENTRIES;
  626.     return DOSFALSE;
  627. }
  628.  
  629. /*
  630.  * Convert AmigaDOS protection bits to messy attribute bits.
  631.  */
  632.  
  633. long
  634. MSSetProtect(parentdir, name, mask)
  635. register struct MSFileLock *parentdir;
  636. char      *name;
  637. long      mask;
  638. {
  639.     register struct MSFileLock *lock;
  640.  
  641.     if (parentdir == NULL)
  642.        parentdir = RootLock;
  643.  
  644.     lock = MSLock(parentdir, name, EXCLUSIVE_LOCK);
  645.     if (lock) {
  646.        /* Leave SYSTEM bit as-is */
  647.        lock->msfl_Msd.msd_Attributes &= ATTR_SYSTEM;
  648.        /* write or delete protected -> READONLY */
  649.        if (mask & (FIBF_WRITE|FIBF_DELETE))
  650.            lock->msfl_Msd.msd_Attributes |= (ATTR_READONLY);
  651.        /* hidden -> hidden */
  652.        if (mask & FIBF_HIDDEN)
  653.            lock->msfl_Msd.msd_Attributes |= (ATTR_HIDDEN);
  654.        /* archived=0 (default) -> archived=1 (default) */
  655.        if (!(mask & FIBF_ARCHIVE))
  656.            lock->msfl_Msd.msd_Attributes |= (ATTR_ARCHIVED);
  657.        WriteFileLock(lock);
  658.        MSUnLock(lock);
  659.        return TRUE;
  660.     }
  661.  
  662.     return FALSE;
  663. }
  664.  
  665. int
  666. CheckLock(lock)
  667. register struct MSFileLock *lock;
  668. {
  669.     register struct MSFileLock *parent;
  670.  
  671.     if (lock) {
  672.        while (parent = lock->msfl_Parent)
  673.            lock = parent;
  674.        if (lock != RootLock)
  675.            error = ERROR_DEVICE_NOT_MOUNTED;
  676.     }
  677.     return error;
  678. }
  679.  
  680. #ifndef READONLY
  681.  
  682. void
  683. WriteFileLock(fl)
  684. register struct MSFileLock *fl;
  685. {
  686.     debug(("WriteFileLock %08lx\n", fl));
  687.  
  688.     if (fl) {
  689.        register byte  *block = GetSec(fl->msfl_DirSector);
  690.  
  691.        if (block) {
  692.            CopyMem(&fl->msfl_Msd, block + fl->msfl_DirOffset,
  693.                    (long) sizeof (fl->msfl_Msd));
  694.            OtherEndianMsd(block + fl->msfl_DirOffset);
  695.            MarkSecDirty(block);
  696.            FreeSec(block);
  697.        }
  698.     }
  699. }
  700.  
  701. void
  702. UpdateFileLock(fl)
  703. register struct MSFileLock *fl;
  704. {
  705.     struct DateStamp dateStamp;
  706.  
  707.     debug(("UpdateFileLock %08lx\n", fl));
  708.  
  709.     DateStamp(&dateStamp);
  710.     ToMSDate(&fl->msfl_Msd.msd_Date, &fl->msfl_Msd.msd_Time, &dateStamp);
  711.     WriteFileLock(fl);
  712. }
  713.  
  714. #endif
  715.  
  716. struct LockList *
  717. NewLockList(cookie)
  718. void          *cookie;
  719. {
  720.     struct LockList *ll;
  721.  
  722.     if (ll = AllocMem((long) sizeof (*ll), MEMF_PUBLIC)) {
  723.        NewList(&ll->ll_List);
  724.        ll->ll_Cookie = cookie;
  725.     } else
  726.        error = ERROR_NO_FREE_STORE;
  727.  
  728.     return ll;
  729. }
  730.  
  731. void
  732. FreeLockList(ll)
  733. struct LockList *ll;
  734. {
  735.     debug(("FreeLockList %08lx\n", ll));
  736.  
  737.     if (ll) {
  738.        MayFreeVolNode(ll->ll_Cookie);  /* not too happy about this */
  739.        FreeMem(ll, (long) sizeof (*ll));
  740.        if (ll == LockList)     /* locks on current volume */
  741.            LockList = NULL;
  742.     }
  743. }
  744.